Open
Conversation
There was a problem hiding this comment.
Pull request overview
This PR introduces a startsWith search operator and adjusts Discovery/Solr indexing and submission-authorized collection search to support case-insensitive prefix matching (primarily on titles). It also refactors several REST components to rely on Spring DI for SubmissionConfigService to avoid early factory/service initialization.
Changes:
- Add
startsWithoperator support in REST/search operator allowlist and Solr filter query generation. - Index container titles into
*_sortfields (and add Discovery config for adc.title-backed filter) to enable prefix matching on communities/collections. - Update integration tests and refactor multiple REST services/repositories/converters to use Spring injection for submission config services.
Reviewed changes
Copilot reviewed 17 out of 17 changed files in this pull request and generated 13 comments.
Show a summary per file
| File | Description |
|---|---|
| dspace/config/spring/api/discovery.xml | Adds a new Discovery search filter bean targeting dc.title and enables it in the filter list. |
| dspace-server-webapp/src/test/java/org/dspace/app/rest/CollectionRestRepositoryIT.java | Updates/extends IT assertions around prefix matching behavior in submit-authorized collection search. |
| dspace-server-webapp/src/main/java/org/dspace/app/rest/submit/SubmissionService.java | Switches SubmissionConfigService initialization to Spring injection (constructor no longer uses factory). |
| dspace-server-webapp/src/main/java/org/dspace/app/rest/repository/WorkspaceItemRestRepository.java | Migrates to constructor injection for SubmissionConfigService. |
| dspace-server-webapp/src/main/java/org/dspace/app/rest/repository/WorkflowItemRestRepository.java | Migrates to constructor injection for SubmissionConfigService. |
| dspace-server-webapp/src/main/java/org/dspace/app/rest/repository/SubmissionPanelRestRepository.java | Migrates to constructor injection for SubmissionConfigService. |
| dspace-server-webapp/src/main/java/org/dspace/app/rest/repository/SubmissionDefinitionRestRepository.java | Migrates to constructor injection for SubmissionConfigService. |
| dspace-server-webapp/src/main/java/org/dspace/app/rest/model/query/RestSearchOperator.java | Adds startsWith to the allowed operator strings. |
| dspace-server-webapp/src/main/java/org/dspace/app/rest/converter/WorkspaceItemConverter.java | Removes exception-throwing constructor to align with DI changes. |
| dspace-server-webapp/src/main/java/org/dspace/app/rest/converter/WorkflowItemConverter.java | Removes exception-throwing constructor to align with DI changes. |
| dspace-server-webapp/src/main/java/org/dspace/app/rest/converter/AInprogressItemConverter.java | Switches submission config wiring to Spring injection in the base converter. |
| dspace-api/src/main/java/org/dspace/discovery/indexobject/CommunityIndexFactoryImpl.java | Adds title_sort field to community Solr documents for prefix matching. |
| dspace-api/src/main/java/org/dspace/discovery/indexobject/CollectionIndexFactoryImpl.java | Adds title_sort field to collection Solr documents for prefix matching. |
| dspace-api/src/main/java/org/dspace/discovery/SolrServiceImpl.java | Implements startsWith operator mapping to _sort fields and wildcard prefix query generation. |
| dspace-api/src/main/java/org/dspace/discovery/SearchService.java | Updates Javadoc to include startsWith as a supported operator. |
| dspace-api/src/main/java/org/dspace/content/CollectionServiceImpl.java | Changes submit-authorized collection search to use dc.title_sort:<prefix>* filtering. |
| dspace-api/src/main/java/org/dspace/app/util/SubmissionConfigReader.java | Changes config directory initialization to be computed via a getter rather than an eager field initializer. |
Comments suppressed due to low confidence (1)
dspace-api/src/main/java/org/dspace/discovery/SolrServiceImpl.java:1308
- In the
startsWithbranch,valueis mutated (lowercased + escaped) before callingtransformDisplayedValue, soDiscoverFilterQuery.displayedValuewill end up escaped/lowercased (e.g.testing\ auto) instead of reflecting the user input. Preserve the original raw value fordisplayedValue(and only use the escaped/lowercased value for the actual filter query).
if ("startsWith".equals(operator)) {
// Lowercase and escape the value, then append wildcard for prefix matching.
// The _sort field uses lowerCaseSort type, so both indexed and query values are lowercased.
value = ClientUtils.escapeQueryChars(value.toLowerCase());
filterQuery.append(value).append("*");
} else if ("equals".equals(operator) || "notequals".equals(operator)) {
//DO NOT ESCAPE RANGE QUERIES !
if (!value.matches("\\[.*TO.*\\]")) {
value = ClientUtils.escapeQueryChars(value);
filterQuery.append(value);
} else {
if (value.matches("\\[\\d{1,4} TO \\d{1,4}\\]")) {
int minRange = Integer.parseInt(value.substring(1, value.length() - 1).split(" TO ")[0]);
int maxRange = Integer.parseInt(value.substring(1, value.length() - 1).split(" TO ")[1]);
value = "[" + String.format("%04d", minRange) + " TO " + String.format("%04d", maxRange) + "]";
}
filterQuery.append(value);
}
} else {
//DO NOT ESCAPE RANGE QUERIES !
if (!value.matches("\\[.*TO.*\\]")) {
value = ClientUtils.escapeQueryChars(value);
filterQuery.append("\"").append(value).append("\"");
} else {
filterQuery.append(value);
}
}
result.setDisplayedValue(transformDisplayedValue(context, field, value));
}
Comment on lines
103
to
108
| private org.dspace.app.rest.utils.Utils utils; | ||
| @Autowired | ||
| private SubmissionConfigService submissionConfigService; | ||
|
|
||
| public SubmissionService() throws SubmissionConfigReaderException { | ||
| submissionConfigService = SubmissionServiceFactory.getInstance().getSubmissionConfigService(); | ||
| public SubmissionService() { | ||
| } |
| if ("startsWith".equals(operator)) { | ||
| // Lowercase and escape the value, then append wildcard for prefix matching. | ||
| // The _sort field uses lowerCaseSort type, so both indexed and query values are lowercased. | ||
| value = ClientUtils.escapeQueryChars(value.toLowerCase()); |
Comment on lines
+788
to
+791
| * Verify that {@code findSubmitAuthorized} implements word-level prefix matching: | ||
| * <ul> | ||
| * <li>"te" must find collections whose title contains a word starting with "te".</li> | ||
| * <li>"es" must NOT find "Test collection" because no word starts with "es".</li> |
Comment on lines
+105
to
+107
| // Also index as "title_sort" so the standard searchFilterTitle-based | ||
| // discovery filter (f.title + startsWith) works for communities. | ||
| doc.addField("title_sort", title); |
Comment on lines
+131
to
+133
| // Also index as "title_sort" so the standard searchFilterTitle-based | ||
| // discovery filter (f.title + startsWith) works for collections. | ||
| doc.addField("title_sort", title); |
Comment on lines
+119
to
122
| @Autowired | ||
| public WorkflowItemRestRepository(SubmissionConfigService submissionConfigService) { | ||
| this.submissionConfigService = submissionConfigService; | ||
| } |
Comment on lines
+1027
to
+1029
| // title that starts with "te" (case-insensitive). | ||
| String lowerQ = ClientUtils.escapeQueryChars(q.trim().toLowerCase()); | ||
| discoverQuery.addFilterQueries("dc.title_sort:" + lowerQ + "*"); |
Comment on lines
59
to
+64
| @Autowired | ||
| SubmissionService submissionService; | ||
| @Autowired | ||
| protected SubmissionConfigService submissionConfigService; | ||
|
|
||
| public AInprogressItemConverter() throws SubmissionConfigReaderException { | ||
| submissionConfigService = SubmissionServiceFactory.getInstance().getSubmissionConfigService(); | ||
| public AInprogressItemConverter() { |
Comment on lines
+42
to
45
| @Autowired | ||
| public SubmissionDefinitionRestRepository(SubmissionConfigService submissionConfigService) { | ||
| this.submissionConfigService = submissionConfigService; | ||
| } |
Comment on lines
+149
to
+151
| @Autowired | ||
| public WorkspaceItemRestRepository(SubmissionConfigService submissionConfigService) { | ||
| this.submissionConfigService = submissionConfigService; |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Problem description
Analysis
(Write here, if there is needed describe some specific problem. Erase it, when it is not needed.)
Problems
(Write here, if some unexpected problems occur during solving issues. Erase it, when it is not needed.)
Manual Testing (if applicable)
Copilot review